using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.ServiceModel;
using System.Text;
using System.Windows.Forms;
using Microsoft.Vsts.Ranger.Migration.TfsToTfs;
using System.Xml.Serialization;
using System.IO;
using Microsoft.Vsts.Ranger.Migration.TfsToTfs.Client.Common;
using Microsoft.Vsts.Ranger.Migration.TfsToTfs.Service.DataContracts;
using Microsoft.Vsts.Ranger.Migration.TfsToTfs.Service.Services;
using Microsoft.Vsts.Ranger.Migration.TfsToTfs.Service.Schemas;
using Microsoft.Vsts.Ranger.Migration.TfsToTfs.Service.Common;

namespace Microsoft.Vsts.Ranger.Migration.TfsToTfs.Client
{
    public partial class MigrationHome : Form
    {

        public MigrationHome()
        {
            InitializeComponent();
        }

        private void PopulateSessions()
        {
            
            MigrationConfig.MigrationElement migration = UIApplicationState.SessionFileManager.MigrationConfig;

            lvwSessions.Items.Clear();

            PopulateVCSessions(migration);
            PopulateWitSessions(migration);


            if (lvwSessions.Items.Count > 0)
                lvwSessions.Items[0].Selected = true;
        }

        private void PopulateWitSessions(MigrationConfig.MigrationElement migration)
        {
            try
            {
                if (migration.WIT != null && migration.WIT.Sessions.Count > 0)
                {
                    foreach (MigrationConfig.WITSessionElement session in migration.WIT.Sessions)
                    {
                        ListViewItem item = new ListViewItem();

                        item.Text = session.id;
                        item.SubItems.Add("Work Item");
                        item.SubItems.Add(session.Tfs.server + "." + session.Tfs.Project);
                        item.SubItems.Add(session.Source.Tfs.server + "." + session.Source.Tfs.Project);

                        lvwSessions.Items.Add(item);
                    }
                }
            }
            catch(Exception ex)
            {
                throw new ArgumentException("Error found loading WIT Sessions.", ex);
            }
        }

        private void PopulateVCSessions(MigrationConfig.MigrationElement migration)
        {
            try
            {
                if (migration.VC != null && migration.VC.Sessions.Count > 0)
                {
                    foreach (MigrationConfig.VCSessionElement session in migration.VC.Sessions)
                    {
                        ListViewItem item = new ListViewItem();

                        item.Text = session.id;
                        item.SubItems.Add("Version Control");
                        item.SubItems.Add(session.Tfs.server + " [" + session.Mappings[0].tgt + "]");
                        item.SubItems.Add(session.Source.Tfs.server + " [" + session.Mappings[0].src + "]");

                        lvwSessions.Items.Add(item);
                    }
                }
            }
            catch (Exception ex)
            {
                throw new ArgumentException("Error found loading VC Sessions.", ex);
            }

        }

        private void MigrationHome_Load(object sender, EventArgs e)
        {
            try
            {
                UIApplicationState.SessionFileManager.LoadMigrationConfig();
            }
            catch (Exception ex)
            {
                ExceptionManager.DisplayExceptionToUser(ex, "Error Loading Configuration File", "Error Loading Configuration File");
            } 
            
            PopulateSessions();

        
        }

        private void btnDelete_Click(object sender, EventArgs e)
        {
            if (EnsureSessionIsSelected())
            {
                string sessionName = lvwSessions.SelectedItems[0].Text;

                if (MessageBox.Show(String.Format("Are you sure that you want to delete {0}?", sessionName), "Confirm Delete", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    try
                    {
                        UIApplicationState.SessionFileManager.DeleteSession(sessionName);
                        UIApplicationState.SessionFileManager.SaveFileChanges();
                        PopulateSessions();
                    }
                    catch (Exception ex)
                    {
                        ExceptionManager.DisplayExceptionToUser(ex, "Error Deleting Session", "Error Deleting Session");
                    }
                }
            }
        }



        private void btnNew_Click(object sender, EventArgs e)
        {
            EditSession sessionForm = new EditSession();
            sessionForm.ShowDialog(this);
            PopulateSessions();

        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (EnsureSessionIsSelected() && ConfirmStartSession(optOneWay.Checked, true))
            {
                string sessionName = lvwSessions.SelectedItems[0].Text;

                MigrationService client = new MigrationService();
                try
                {
                    if (optOneWay.Checked)
                        client.StartSession(sessionName, true);
                    else
                        client.StartSession(sessionName, false);

                }
                catch (TimeoutException timeout)
                {
                    ExceptionManager.DisplayExceptionToUser(timeout, "The service operation timed out. ");
                }
                catch (FaultException<ServerError> serverError)
                {
                    ExceptionManager.DisplayExceptionToUser(serverError, serverError.ToString());
                }
                catch (FaultException unknownFault)
                {
                    ExceptionManager.DisplayExceptionToUser(unknownFault, "An unknown exception was received.");
                }
                catch (CommunicationException communicationException)
                {
                    ExceptionManager.DisplayExceptionToUser(communicationException, "There was a communication problem.");
                }
            }
        }

        private void btnGetSessions_Click(object sender, EventArgs e)
        {
            LoadSessionItems();
        }

        private void btnStartMirror_Click(object sender, EventArgs e)
        {
            if (EnsureSessionIsSelected() && ConfirmStartSession(optOneWay.Checked, false))
            {
                MigrationService client = new MigrationService();
                
                try
                {
                    if (optOneWay.Checked)
                        client.StartMirror(lvwSessions.SelectedItems[0].Text, true);
                    else
                        client.StartMirror(lvwSessions.SelectedItems[0].Text, false);

                }
                catch (TimeoutException timeout)
                {
                    ExceptionManager.DisplayExceptionToUser(timeout, "The service operation timed out. ");
                }

                catch (FaultException<ServerError> serverError)
                {
                    ExceptionManager.DisplayExceptionToUser(serverError, serverError.ToString());
                }
                catch (FaultException unknownFault)
                {
                    ExceptionManager.DisplayExceptionToUser(unknownFault, "An unknown exception was received.");
                }
                catch (CommunicationException communicationException)
                {
                    ExceptionManager.DisplayExceptionToUser(communicationException, "There was a communication problem.");
                }
            }
        }

        private void MigrationHome_FormClosing(object sender, FormClosingEventArgs e)
        {
            if ( LocalServiceHost.Running)
                LocalServiceHost.StopService();
        }

        private void grpStartType_Enter(object sender, EventArgs e)
        {

        }

        private void timerRefresh_Tick(object sender, EventArgs e)
        {
            LoadSessionItems();
        }

        private void LoadSessionItems()
        {
            MigrationService client = new MigrationService();
            try
            {
                int selectedInstanceId = -1;

                //Store the previously selected Item id
                if (lvwRunningSessions.SelectedItems.Count > 0)
                {
                    selectedInstanceId = (int)lvwRunningSessions.SelectedItems[0].Tag;
                }


                SessionsDataset ds = client.GetSessionInstances(chkIncludeCompleted.Checked);

                //Clear out the old events
                lvwRunningSessions.Items.Clear();
                lvwEvents.Items.Clear();


                foreach (SessionsDataset.SessionInstancesRow row in ds.SessionInstances)
                {
                    ListViewItem item = new ListViewItem();

                    item.Text = row.SessionID;
                    item.SubItems.Add(row.StartTime.ToString());
                    item.SubItems.Add(DateTime.Now.Subtract(row.StartTime).ToString());
                    item.SubItems.Add(row.CurrentStatus);

                    item.SubItems.Add((row.OneTimeOnly) ? "One-Time" : "Mirroring");

                    item.Tag = row.SessionInstanceID;

                    //Re-select the one that the user had selected
                    if (selectedInstanceId != -1 && selectedInstanceId == row.SessionInstanceID)
                        item.Selected = true;

                    lvwRunningSessions.Items.Add(item);

                }

                //Select the 1st item in the listview if none are currently selected
                if (selectedInstanceId == -1 && lvwRunningSessions.Items.Count > 0)
                    lvwRunningSessions.Items[0].Selected = true;


                //Load up the session events if a session is selected
                if (lvwRunningSessions.SelectedItems.Count > 0)
                {
                    int sessionInstanceId = (int)lvwRunningSessions.SelectedItems[0].Tag;
                    LoadEventsForSession(sessionInstanceId);
                }

            }
            catch (TimeoutException timeout)
            {
                //Disable the timer control so that the user doesnt get spammed with error messages
                timerRefresh.Enabled = false;

                ExceptionManager.DisplayExceptionToUser(timeout, "The service operation timed out. ");
            }

            catch (FaultException<ServerError> serverError)
            {
                //Disable the timer control so that the user doesnt get spammed with error messages
                timerRefresh.Enabled = false;


                ExceptionManager.DisplayExceptionToUser(serverError, serverError.ToString());
                //client.Abort();
            }
            catch (FaultException unknownFault)
            {
                //Disable the timer control so that the user doesnt get spammed with error messages
                timerRefresh.Enabled = false;

                ExceptionManager.DisplayExceptionToUser(unknownFault, "An unknown exception was received.");
            }
            catch (CommunicationException communicationException)
            {
                //Disable the timer control so that the user doesnt get spammed with error messages
                timerRefresh.Enabled = false;

                ExceptionManager.DisplayExceptionToUser(communicationException, "There was a communication problem.");
            }
            catch (Exception ex)
            {
                //Disable the timer control so that the user doesnt get spammed with error messages
                timerRefresh.Enabled = false;

                ExceptionManager.DisplayExceptionToUser(ex, "Error Loading Sessions", "Error Loading Sessions");
            }
        }


        private void LoadEventsForSession(int sessionInstanceId)
        {
            MigrationService client = new MigrationService();

            try
            {
                lvwEvents.Items.Clear();

                System.Diagnostics.Debug.WriteLine("Before call: " + DateTime.Now);
                SessionsDataset ds = client.GetEventsForSessionInstance(sessionInstanceId);
                System.Diagnostics.Debug.WriteLine("After call: " + DateTime.Now);

                foreach (SessionsDataset.EventsRow row in ds.Events)
                {
                    ListViewItem item = new ListViewItem();
                    item.Text = row.EventType;
                    item.SubItems.Add(row.Description);
                    item.SubItems.Add(row.Time.ToString());

                    lvwEvents.Items.Add(item);
                }
            }
            catch (TimeoutException timeout)
            {
                ExceptionManager.DisplayExceptionToUser(timeout, "The service operation timed out. ");
            }
            catch (FaultException unknownFault)
            {
                ExceptionManager.DisplayExceptionToUser(unknownFault, "An unknown exception was received.");
            }
            catch (CommunicationException communicationException)
            {
                ExceptionManager.DisplayExceptionToUser(communicationException, "There was a communication problem.");
            }
            catch (Exception ex)
            {
                ExceptionManager.DisplayExceptionToUser(ex, "Error Loading Event Sessions", "Error Loading Sessions");
            }
        }

        private void MigrationHome_Activated(object sender, EventArgs e)
        {
            this.Refresh();
        }

        private void lvwRunningSessions_SelectedIndexChanged(object sender, EventArgs e)
        {
        }

        private bool EnsureSessionIsSelected()
        {
            if (lvwSessions.SelectedItems.Count < 1)
            {
                MessageBox.Show("Please select a Session from the list.", "Session Not Selected", MessageBoxButtons.OK, MessageBoxIcon.Information);
                return false;
            }
            else
            {
                return true;
            }
        }

        private bool ConfirmStartSession(bool oneWay, bool oneTimeOnly)
        {
            bool? isServiceOwnerAdmin;
            string serviceOwnerNote = string.Empty;

            try
            {
                isServiceOwnerAdmin = ServiceOwnerValidator.IsServiceOwnerAnAdmin(Constants.CMIGRATIONSERVICENAME);

                if (!isServiceOwnerAdmin.HasValue)
                {
                    serviceOwnerNote = string.Format(
                        "NOTE: Please make sure that {0} is run by an account in the Windows Administrator group.\n\n\n",
                        Constants.CMIGRATIONSERVICENAME);
                }
                else if (!isServiceOwnerAdmin.Value)
                {
                    serviceOwnerNote = string.Format(
                        "NOTE: {0} is not run by an account in the Windows Administrator group. Your session will be pending until you grant the service owner with the requisite permission.\n\n\n",
                        Constants.CMIGRATIONSERVICENAME);
                }
            }
            catch (ServiceOwnerValidator.ServiceNotExistException)
            {
                serviceOwnerNote = string.Format(
                        "NOTE: {0} is not installed. Your session will be pending until you install and run the service with an account in the Windows Administrator group.\n\n\n",
                        Constants.CMIGRATIONSERVICENAME);
            }
            catch (ServiceOwnerValidator.ServiceNotRunningException)
            {
                serviceOwnerNote = string.Format(
                        "NOTE: {0} is not running. Your session will be pending until it run by an account in the Windows Administrator group.\n\n\n",
                        Constants.CMIGRATIONSERVICENAME);
            }
            

            string sessionName = lvwSessions.SelectedItems[0].Text;

            string directionMessage = (oneWay)?"One-Way (Source to Destination Only)":"Bi-Directional (Move Items Both Ways)";
            string oneTimeMessage = (oneTimeOnly)? "One Time only (not an ongoing Syncronization)": "Mirror (Ongoing Syncronization)";
            string message = String.Format(
                "{0}Confirming session start:\n\nSession Name:\t{1}\nDirection:\t\t{2}\nStart Type:\t{3}\n\nAre you sure that you want to start this session?", 
                serviceOwnerNote,
                sessionName, 
                directionMessage, 
                oneTimeMessage);

            if (MessageBox.Show(message, "Confirm Start Session", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        private void btnStopSession_Click(object sender, EventArgs e)
        {
            MigrationService client = new MigrationService();
            
            try
            {
                //Store the previously selected Item id
                if (lvwRunningSessions.SelectedItems.Count > 0)
                {
                    int selectedInstanceId = (int)lvwRunningSessions.SelectedItems[0].Tag;
                    string sessionName = lvwRunningSessions.SelectedItems[0].Text;

                    //Determine whether to call StopService or StopMirror
                    //TODO: Need to clean this code up, sub-class the ListItem so that we have strong typing for list items
                    if (lvwRunningSessions.SelectedItems[0].SubItems[3].Text == "One-Time")
                    {
                        client.StopSession(sessionName, selectedInstanceId);
                    }
                    else
                    {
                        client.StopMirror(sessionName, selectedInstanceId);
                    }

                    //Re-load the sessions
                    LoadSessionItems();


                }
                else
                {
                    MessageBox.Show("Please select the item that you'd like to stop.", "No Item Selected", MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
                }
            }
            catch (TimeoutException timeout)
            {
                ExceptionManager.DisplayExceptionToUser(timeout, "The service operation timed out. ");
            }
            
            catch (FaultException<ServerError> serverError) 
            {
                ExceptionManager.DisplayExceptionToUser(serverError, serverError.ToString());
            }
            catch (FaultException unknownFault)
            {
                ExceptionManager.DisplayExceptionToUser(unknownFault, "An unknown exception was received.");
            }
            catch (CommunicationException communicationException)
            {
                ExceptionManager.DisplayExceptionToUser(communicationException, "There was a communication problem.");
            }
            catch (Exception ex)
            {
                ExceptionManager.DisplayExceptionToUser(ex, "Error Stopping Session", "Error Stopping Session");
            }

        }

        private void chkRefreshEnabled_CheckedChanged(object sender, EventArgs e)
        {
            if (chkRefreshEnabled.Checked)
                timerRefresh.Enabled = true;
            else
                timerRefresh.Enabled = false;
        }
    }
}
